package platform.service.inv;

import org.mvel2.MVEL;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

public class Inv {
    String expression;
    Object instance;
    Method method;
    String[] params;

    public Inv(String expression) {
        this.expression = expression;
        this.instance = null;
        this.method = null;
        this.params = null;
    }

    public boolean check(Map<String, Object> values) {
        // 计算表达式的值
        if (method != null) {
            try {
                return (boolean) invoke(values);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        } else {
            try {
                return (boolean) eval(expression, values);
            } catch (Exception e) {
                // 如果解析失败，尝试使用反射执行自定义方法
                try {
                    return (Boolean) reflectAndInvoke(values);
                } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
                         InvocationTargetException ex) {
                    ex.printStackTrace();
                }
            }
        }
        return false;
    }

    private Object reflectAndInvoke(Map<String, Object> values)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {
        try {
            // 解析字符串
            // "com.example.package.A.b.c.func()"
            String path = expression.substring(0, expression.indexOf('('));
            params = expression.substring(expression.indexOf('(') + 1, expression.length() - 1).
                    replace(" ","").split(",");
            String[] parts = path.split("\\.");
            int[] dotIndexes = new int[parts.length - 1];
            int length = 0;
            for (int i = 0; i < dotIndexes.length; i++) {
                dotIndexes[i] = length + parts[i].length();
                length += parts[i].length() + 1;
            }

            String methodName = parts[parts.length - 1];

            // 尝试获取类
            Class<?> clazz = null;
            int endIndex = parts.length - 2;
            while (clazz == null && endIndex >= 0) {
                try {
                    String className = expression.substring(0, dotIndexes[endIndex]);
                    clazz = Class.forName(className);
                } catch (ClassNotFoundException e) {
                    endIndex--;
                }
            }

            if (clazz != null) {
                // 如果存在变量名，获取变量的Field对象，并设置为可访问
                for (int i = endIndex + 1; i < parts.length - 1; i++) {
                    Field field = clazz.getDeclaredField(parts[i]);
                    field.setAccessible(true);
                    instance = field.get(instance);
                    clazz = instance.getClass();
                }

                // 获取类中声明的所有方法
                Method[] methods = clazz.getDeclaredMethods();

                // 遍历方法，找到名为methodName的方法
                for (Method m : methods) {
                    if (m.getName().equals(methodName)) {
                        method = m;
                        break;
                    }
                }

                if (method != null) {
                    // 找到了目标方法
                    return invoke(values);
                } else {
                    // 没有找到目标方法
                    return false;
                }
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    //调用函数
    public Object invoke(Map<String, Object> values) {
        Object[] args = new Object[params.length];
        for (int i = 0; i < params.length; i++) {
            args[i] = eval(params[i], values);
        }
        try {
            Object ret = method.invoke(instance, args);
//            System.out.println(ret);
            return ret;
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return false;
    }

    //计算简单表达式的值
    public Object eval(String expr, Map<String, Object> values) {
        // expr: x + xy
        // values: {x: 1, xy: 2}
        // return: 3
        Object ce = MVEL.compileExpression(expr);
        Object ret = MVEL.executeExpression(ce, values);
//        System.out.println(ret);
        return ret;
    }

    @Override
    public String toString() {
        return expression;
    }

    public static void main(String[] args) {
        Inv inv = new Inv("y == (z / x)");
        System.out.println(inv.check(Map.of("z", 0, "y", 0, "x", 0)));
        System.out.println(inv.check(Map.of("z", 0, "y", 0, "x", 1)));
        System.out.println(inv.check(Map.of("z", 4, "y", 2, "x", 2)));
    }
}
